home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-12-16 | 45.1 KB | 1,006 lines |
- /* > c.GetDirs - (c) Paul Witheridge - Version 2.00 - 07 Dec 1991 */
-
- /*===================================================================*/
- /* */
- /* Getdirentrys */
- /* ------------ */
- /* */
- /* Getdirentrys is a function which reads entries from a directory */
- /* and then invokes a caller-supplied function to process each */
- /* file-object, passing the directory entry details in a 'direntry' */
- /* structure defined in 'getdirs.h'. */
- /* */
- /* The caller supplies the name of the directory to be read (plus */
- /* optionally, a wildcarded or non-wildcarded object name to be */
- /* matched against objects in the directory), an indicator as to */
- /* whether any subdirectories found should be read (recursively) */
- /* and a pointer to the caller's function to process the entries. */
- /* */
- /* The global integer variable "getdirentrys_counter" counts the */
- /* the number of objects passed to the caller's function. */
- /* */
- /* The caller's function should return a value of 'TRUE' if it has */
- /* not encountered any fatal errors, or 'FALSE' if it wants to */
- /* stop processing of any further directory entries. */
- /* */
- /*-------------------------------------------------------------------*/
- /* */
- /* This file includes the following functions: */
- /* */
- /* getdirentrys - read and process directory entries */
- /* buildtree - internal (static) recursive function */
- /* processtree - internal (static) recursive function */
- /* extendpath - internal (static) function */
- /* freetree - internal (static) recursive function */
- /* beep - sound two tone beep */
- /* */
- /*-------------------------------------------------------------------*/
- /* */
- /* COPYRIGHT NOTICE */
- /* */
- /* GetDirs is subject to Copyright. */
- /* */
- /* Permission is granted by the author to any recipient of this */
- /* material to use and make/disseminate copies of the application */
- /* provided that no charges are made for doing so (other than to */
- /* cover any cost of media or postage) and that this notice is */
- /* included with all copies. */
- /* */
- /*===================================================================*/
-
- #include "kernel.h" /* ARC specifics */
- #include <ctype.h> /* Character handling */
- #include <limits.h> /* Implementation limits */
- #include <stddef.h> /* Standard defintions */
- #include <stdio.h> /* Input/output */
- #include <stdlib.h> /* General utilities */
- #include <string.h> /* String handling */
-
- #include "getdirs.h" /* GetDirs header */
- #include "useful.h" /* Useful defns */
-
- /*-------------------------------------------------------------------*/
- /* Global data declarations and definitions. */
- /*-------------------------------------------------------------------*/
-
- #define maxpathlen 255 /* Max path length */
- #define maxobjectlen 20 /* Max object length */
- #define maxdirlistlen 1024 /* Max directory list length */
-
- struct dirblock /* Directory list structure */
- {
- struct dirblock *subdirq ; /* Ptr to subdirectory tree */
- struct dirblock *nextptr ; /* Ptr to next list */
- int nobjects ; /* No. of objects in this list */
- int handle ; /* Handle (id) for this list */
- char dirlist[maxdirlistlen] ; /* List of nul-term'd objects */
- } ;
-
- int getdirentrys_counter ; /* Count of files processed */
-
- static enum boolean (*funcptr)( /* Ptr to function */
- const char *path,
- direntry *ptr) ;
-
- static const char toolong[] = /* Common error message */
- "'%s' too long" ;
-
- static const char outofmemory[] = /* Common error message */
- "out of memory" ;
-
- static const char invalidentry[] = /* Common error message */
- "Invalid directory entry '%s'\n" ;
-
- /*-------------------------------------------------------------------*/
- /* Declare functions local in scope to this file. */
- /*-------------------------------------------------------------------*/
-
- static enum boolean buildtree( /* Build directory list tree */
- char *path,
- const char *object,
- const enum recursive recursion,
- const int handle,
- struct dirblock **subdirq) ;
-
- static enum boolean processtree( /* Process directory list tree */
- char *path,
- struct dirblock *dirblkptr) ;
-
- static enum boolean extendpath( /* Add leafname to path */
- char *path,
- int pathlen,
- const char *leafname) ;
-
- static void freetree( /* Free directory list tree */
- struct dirblock **subdirq) ;
-
- /*===================================================================*/
- /* */
- /* getdirentrys - read directory entries */
- /* ------------ */
- /* */
- /* This function is called to read entries from a caller-specified */
- /* directory and pass details of any entries for file objects to a */
- /* caller-supplied function. It is intended for use with a non */
- /* multitasking utility, since it may write error messages to the */
- /* standard output stream. */
- /* */
- /* The caller provides three arguments: */
- /* */
- /* (1) Directory name and optional object name. This may be a fully */
- /* qualified name (e.g. 'adfs::IDEDisc4.$.Clib.h') or it may be */
- /* relative to the currently selected directory (e.g. just 'h' */
- /* if the CSD is 'adfs::IDEDisc4.$.Clib' or '^.h' if the CSD is */
- /* 'adfs::IDEDisc4.$.Clib.o'). It may end with a wild-carded or */
- /* non-wildcarded object name which will be used to select */
- /* objects from the director (e.g. 'h.a*' meaning all file */
- /* objects beginning with 'a' in directory 'h' which is a sub- */
- /* directory of the CSD). */
- /* */
- /* (2) A switch indicating whether any subdirectories found in the */
- /* specified directory are to be processed or not. This can take */
- /* one of three values 'RECURSE_NEVER', 'RECURSE_ONCE' or */
- /* 'RECURSE_ALWAYS'. These are defined in 'getdirs.h'. They have */
- /* the following effect: */
- /* */
- /* RECURSE_NEVER implies that the caller knows that the first */
- /* argument is in the form 'directory.object', and that object */
- /* is a (possibly wildcarded) file leafname. Only file objects */
- /* in 'directory' are to be processed; any subdirectories are */
- /* to be ignored. So if 'object' turned out to be a directory */
- /* name it would be ignored. This value would only be used under */
- /* special circumstances. */
- /* */
- /* RECURSE_ONCE implies that the caller is unsure whether the */
- /* first argument is in the form 'directory.object' or just */
- /* 'directory'. If it turns out to be a directory, then all the */
- /* file objects in that directory are to be processed, but any */
- /* subdirectories are to be ignored. This would be the normal */
- /* value to use if subdirectories were not to be processed. */
- /* */
- /* RECURSE_ALWAYS implies full recursion. All files matching */
- /* 'object' found in directory will be processed. All sub- */
- /* directories matching 'object' will be read; all files in them */
- /* will be processed and all subdirectories found will be read */
- /* recursively. */
- /* */
- /* (3) A pointer to a function which will process the file-objects. */
- /* It will be called once for each file-object found in the */
- /* specified directory (and all subdirectories if argument 2 */
- /* specifies recursive processing of subdirectories). It is */
- /* passed the name of the directory and a pointer to the details */
- /* from the directory in a 'direntry' structure. These details */
- /* include the object-name, its load and exec addresses (which */
- /* may be in the form of file-type and time-stamp), its length, */
- /* and its attributes. The file-type is extracted from the load */
- /* address and supplied separately (or as 0xFFFFFFFF if the file */
- /* has no file-type and time-stamp). This function should return */
- /* a value of 'FALSE' to halt further processing, or 'TRUE' to */
- /* continue processing of the directory entries. */
- /* */
- /* Getdirentrys returns a value of TRUE if it encountered no errors */
- /* in reading the directory entries and if the caller-supplied */
- /* function always returns 'TRUE'. Getdirentrys returns a value of */
- /* 'FALSE' if it encountered any errors reading the directory, or if */
- /* the caller-supplied function returned a value of FALSE. The */
- /* values 'TRUE' and 'FALSE' are defined in 'useful.h'. */
- /* */
- /* Two passes are made through the directory (and subdirectories if */
- /* recursive processing required). The first pass is performed by */
- /* calling the internal function 'buildtree' which creates a tree */
- /* of 'dirlist' structures listing the current contents of the */
- /* directories. The second pass is performed by calling the internal */
- /* function 'processtree' which checks that each file-object in the */
- /* tree structure is still present, and if so invokes the caller- */
- /* supplied function. */
- /* */
- /* The two passes are made in this way so that the caller-supplied */
- /* function is only invoked for objects that already exist, and not */
- /* for any objects that the caller-supplied function may create. */
- /* Otherwise, potentially infinite loops could occur - not really */
- /* infinite because they would stop when directory of disk full */
- /* conditions occurred. */
- /* */
- /* The internal function 'freetree' is used to free up the memory */
- /* allocated to the tree structure. */
- /* */
- /* The counter 'getdirentrys_counter' is used to count the number of */
- /* times the caller-supplied function is invoked. This count is */
- /* available (as an external variable) to the original caller of */
- /* 'getdirentrys' when thus returns. */
- /* */
- /*===================================================================*/
-
- enum boolean getdirentrys(
- const char *fname, /* Ptr to initial name */
- const enum recursive recursion, /* Recursion switch */
- enum boolean (*func)( /* Ptr to function */
- const char *path,
- direntry *ptr))
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions. */
- /*-----------------------------------------------------------------*/
-
- char *p ; /* Working pointer */
- int pathlen ; /* Path length */
- struct dirblock *dirblkptr ; /* Ptr to directory tree */
- enum boolean result ; /* Value to be returned */
- char path[maxpathlen+1] ; /* Path work area */
- char object[maxobjectlen+1] ; /* Object work area */
- static char asterisk[] = "*" ; /* Default object */
- static const char specials[] = /* Special directory letters */
- "@$^\\&%" ;
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* First zero counter in case of immediate exit. */
- /*-----------------------------------------------------------------*/
-
- getdirentrys_counter = 0 ;
-
- /*-----------------------------------------------------------------*/
- /* Copy argument "fname" to variable "path" where it can be worked */
- /* on. Strip leading blanks and quotes; then copy up to, but not */
- /* including, first blank or quote (or to end of string). Take */
- /* FALSE exit immediately if it is too long. */
- /*-----------------------------------------------------------------*/
-
- if ( strlen(fname) > maxpathlen - 3 )
- {
- printf(toolong,fname) ;
- beep() ;
- return FALSE ;
- }
-
- strcpy(path,fname + strspn(fname," \"")) ;
- pathlen = strcspn(path," \"") ;
- path[pathlen] = '\0' ;
-
- /*-----------------------------------------------------------------*/
- /* If argument is null then default to current directory. */
- /*-----------------------------------------------------------------*/
-
- if ( pathlen == 0 )
- {
- strcpy(path,"@") ;
- pathlen = 1 ;
- }
-
- /*-----------------------------------------------------------------*/
- /* If argument incorporates any periods, split into path and */
- /* object at last period. */
- /*-----------------------------------------------------------------*/
-
- if ( ( p = strrchr(path,'.') ) != NULL )
- {
- pathlen = p - path ;
- p++ ;
- }
-
- /*-----------------------------------------------------------------*/
- /* If no period, check for a colon which could be either end of a */
- /* filing system name or start of a disk name. */
- /* */
- /* If just name of a filing system (e.g. adfs:) then add "@" and */
- /* set object to "*". */
- /* */
- /* If filing system name plus special directory letter or disk */
- /* name (e.g. adfs:@ or adfs::IDEDisk4) then just set object to */
- /* "*". */
- /* */
- /* If filing system name plus object name (e.g. adfs:myfile) then */
- /* split into path and object just after ":" and add "@" to the */
- /* filing system name. */
- /*-----------------------------------------------------------------*/
-
- else if ( ( p = strchr(path,':') ) != NULL )
- {
- p++ ;
- if ( *p == '\0' )
- {
- path[pathlen++] = '@' ;
- p = asterisk ;
- }
- else if ( ( *(p + 1) == '\0' && strchr(specials,*p) != NULL ) ||
- ( *p == ':' ) )
- {
- p = asterisk ;
- }
- else
- {
- memmove(p + 1,p,strlen(p) + 1) ;
- *p = '@' ;
- p++ ;
- pathlen = p - path ;
- }
- }
-
- /*-----------------------------------------------------------------*/
- /* No period or colon found. */
- /* */
- /* If argument is just a directory letter (e.g. @ or $) then just */
- /* set object to "*". */
- /* */
- /* Otherwise treat entire argument as the object name and set the */
- /* path to "@". */
- /*-----------------------------------------------------------------*/
-
- else
- {
- if ( pathlen == 1 && strchr(specials,path[0]) != NULL )
- {
- p = asterisk ;
- }
- else
- {
- p = path + 1 ;
- memmove(p,path,strlen(path) + 1) ;
- *p = '@' ;
- pathlen = 1 ;
- }
- }
-
- /*-----------------------------------------------------------------*/
- /* Copy the object to variable "object" and store terminating nul */
- /* at end of the path. Take FALSE exit if the object name is too */
- /* long. */
- /*-----------------------------------------------------------------*/
-
- if ( strlen(p) > maxobjectlen )
- {
- printf(toolong,p) ;
- beep() ;
- return FALSE ;
- }
- strcpy(object,p) ;
-
- path[pathlen] = '\0' ;
-
- /*-----------------------------------------------------------------*/
- /* Copy function pointer to global variable (to avoid need to pass */
- /* same value on when recursing). Set anchor word for directory */
- /* list tree to NULL. Then invoke buildtree to create directory */
- /* list tree and processtree to process the entries in the tree. */
- /*-----------------------------------------------------------------*/
-
- funcptr = func ;
- dirblkptr = NULL ;
-
- if ( ( result = buildtree(path,object,recursion,0,&dirblkptr) ) == TRUE )
- {
- if ( dirblkptr != NULL )
- {
- result = processtree(path,dirblkptr) ;
- freetree(&dirblkptr) ;
- }
- }
-
- /*-----------------------------------------------------------------*/
- /* Return to caller. */
- /*-----------------------------------------------------------------*/
-
- return result ;
- }
-
- /*===================================================================*/
- /* */
- /* buildtree - build tree of directory entry lists */
- /* --------- */
- /* */
- /* This function is called to create a list of entries in the */
- /* target directory that match a (possibly wildcarded) object name. */
- /* This function will also invoke itself recursively, if required, */
- /* to process subdirectories. */
- /* */
- /* The caller provides as arguments: */
- /* */
- /* path - the name of the directory to be searched, must */
- /* include the path (if any) and leafname */
- /* */
- /* object - wildcarded object name used in selecting directory */
- /* entries */
- /* */
- /* recursion - switch indicating if matching files only are to be */
- /* processed (RECURSE_NEVER), or first dirctory if no */
- /* matching files found (RECURSE_ONCE), or all */
- /* matching files and directives are to be processed */
- /* recursively (RECURSE_ALWAYS) */
- /* */
- /* handle - identifier used later to identify this entry */
- /* */
- /* subdirq - pointer to anchor word on which to queue the */
- /* directory list if it is successfully built. */
- /* */
- /* If the function completes successfully, it returns a value of */
- /* TRUE (and if any matching directory entries were found, it queues */
- /* the directory list it has built off the anchor word provided by */
- /* the caller). */
- /* */
- /* If an error is encountered, it returns FALSE. In this case no */
- /* directory list is built. */
- /* */
- /*===================================================================*/
-
- static enum boolean buildtree(
- char *path, /* Directory path */
- const char *object, /* Object (wildcarded) */
- const enum recursive recursion, /* Recursion switch */
- int handle, /* Id provided by caller */
- struct dirblock **subdirq) /* Ptr to subdir queue anchor */
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions */
- /*-----------------------------------------------------------------*/
-
- int pathlen ; /* Length of path string */
- int found ; /* Found switch */
- int i ; /* Working integer */
- char *dataptr ; /* Working pointer */
- struct dirblock *dirblkptr ; /* Directory list block ptr */
- struct dirblock *dirwrkptr ; /* Working dir list block ptr */
- _kernel_osgbpb_block gbpbblk ; /* OS_GBPG parameter block */
- _kernel_osfile_block fileblk ; /* OS_File parameter block */
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* First save length of path on entry so that path can be */
- /* truncated again to this length on exit. Also set found flag to */
- /* value of FALSE (it will be set to TRUE later if any files found */
- /* to process. */
- /*-----------------------------------------------------------------*/
-
- pathlen = strlen(path) ;
- found = FALSE ;
-
- /*-----------------------------------------------------------------*/
- /* Next allocate memory for table of directory names. Take FALSE */
- /* exit if unable to do so. Otherwise initialise control fields at */
- /* head of table: number of names in table set to zero, anchor */
- /* field for subdirectory queue and chain pointer used to queue */
- /* block off parent table are set to null, and handle provided by */
- /* caller store in header. */
- /*-----------------------------------------------------------------*/
-
- if ( ( dirblkptr = malloc(sizeof(struct dirblock)) ) == NULL )
- {
- puts(outofmemory) ;
- beep() ;
- goto badbuild3 ;
- }
- dirblkptr->nobjects = 0 ;
- dirblkptr->subdirq = dirblkptr->nextptr = NULL ;
- dirblkptr->handle = handle ;
-
- /*-----------------------------------------------------------------*/
- /* Use OS_GBPB to read list of names in directory that match the */
- /* (possibly wildcarded) object name provided by the caller. This */
- /* is done as a repetitive process until an OS_GBPB indicates that */
- /* no more entries remain (probably only ever go through loop once */
- /* but the RICS-OS PRM states that not all filing systems may be */
- /* able to do it in one go). If zero entries are obtained but the */
- /* returned values indicate that the end of the directory has not */
- /* been reached, then the buffer is full. In this case issue an */
- /* error message and go take the FALSE exit */
- /*-----------------------------------------------------------------*/
-
- gbpbblk.dataptr = dirblkptr->dirlist ;
- dataptr = dirblkptr->dirlist + sizeof(dirblkptr->dirlist) ;
- gbpbblk.fileptr = 0 ;
- gbpbblk.wild_fld = (char *)object ;
-
- do
- {
- gbpbblk.nbytes = INT_MAX ;
- gbpbblk.buf_len = dataptr - (char *)gbpbblk.dataptr ;
- if ( _kernel_osgbpb(9,(unsigned)path,&gbpbblk) == _kernel_ERROR )
- {
- printf("%s\n",_kernel_last_oserror()->errmess) ;
- goto badbuild1 ;
- }
- for ( i = 0 ; i < gbpbblk.nbytes ; i++ )
- {
- gbpbblk.dataptr = (char *)gbpbblk.dataptr +
- strlen((char *)gbpbblk.dataptr) + 1 ;
- }
- dirblkptr->nobjects += gbpbblk.nbytes ;
- if ( gbpbblk.fileptr == -1 )
- {
- break ;
- }
- if ( gbpbblk.nbytes == 0 )
- {
- printf("Too many objects in directory %s\n",path) ;
- goto badbuild1 ;
- }
- } FOREVER ;
-
- /*-----------------------------------------------------------------*/
- /* If no matching entries found in the directory, go take TRUE */
- /* exit immediately (which will cause directory list block to be */
- /* freed instead of queued because found flag is not set). */
- /*-----------------------------------------------------------------*/
-
- if ( dirblkptr->nobjects == 0 )
- {
- goto goodbuild ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Otherwise free unused space at end of the directory list block. */
- /* Allow for possible NULL return from realloc although it does */
- /* not seem likely since we are shortening the block. */
- /*-----------------------------------------------------------------*/
-
- dirwrkptr = realloc(dirblkptr,offsetof(struct dirblock,dirlist) +
- (char *)gbpbblk.dataptr - dirblkptr->dirlist) ;
- if ( dirwrkptr != NULL )
- {
- dirblkptr = dirwrkptr ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Loop through list of directory entries checking which ones are */
- /* files and which ones are subdirectories using OS_File type 13 */
- /* to read the catalog details for each object (note: a period */
- /* must be added to the end of the path for OS_File). */
- /*-----------------------------------------------------------------*/
-
- for ( i = 0 , dataptr = dirblkptr->dirlist ;
- i < dirblkptr->nobjects ;
- i++ , dataptr += strlen(dataptr) + 1 )
- {
- strcpy(path + pathlen,".") ;
- fileblk.start = (int)path ;
- switch ( _kernel_osfile(13,dataptr,&fileblk) )
- {
- /*-------------------------------------------------------------*/
- /* Returned value = 1 (file found). Set file found flag. */
- /*-------------------------------------------------------------*/
-
- case 1 :
-
- found = TRUE ;
- break ;
-
- /*-------------------------------------------------------------*/
- /* Returned value = 2 (directory found). If recursion always */
- /* required, call ouselves recursively to build directory list */
- /* block for the subdirectory. If not just skip the directory. */
- /*-------------------------------------------------------------*/
-
- case 2 :
-
- if ( recursion == RECURSE_ALWAYS )
- {
- if ( !extendpath(path,pathlen,dataptr) )
- {
- goto badbuild2 ;
- }
- if ( !buildtree(path,"*",RECURSE_ALWAYS,
- (int)dataptr,&dirblkptr->subdirq) )
- {
- goto badbuild2 ;
- }
- }
- break ;
-
- /*-------------------------------------------------------------*/
- /* Returned value = -2 (error occurred). Display error message */
- /* and go take FALSE exit. */
- /*-------------------------------------------------------------*/
-
- case _kernel_ERROR :
-
- printf("%s\n",_kernel_last_oserror()->errmess) ;
- goto badbuild1 ;
-
- /*-------------------------------------------------------------*/
- /* Other value should not occur. Being paranoid, if they do */
- /* just display a message and go take FALSE exit. */
- /*-------------------------------------------------------------*/
-
- default :
-
- printf(invalidentry,dataptr) ;
- goto badbuild1 ;
- }
-
- /*---------------------------------------------------------------*/
- /* Truncate path to original length. */
- /*---------------------------------------------------------------*/
-
- path[pathlen] = '\0' ;
- }
-
- /*-----------------------------------------------------------------*/
- /* If no files were found then all the entries must have been for */
- /* subdirectories. If blanket recursion (RECURSE_ALWAYS) was not */
- /* required, none of them were processed. If RECURSE_ONCE was */
- /* specified, process the first entry only by invoking ourselves */
- /* recursively (but prevent any deeper recursion by specifying */
- /*-----------------------------------------------------------------*/
-
- if ( !found && recursion == RECURSE_ONCE )
- {
- dirblkptr->nobjects = 1 ;
- dirwrkptr = realloc(dirblkptr,offsetof(struct dirblock,dirlist) +
- strlen(dirblkptr->dirlist) + 1) ;
- if ( dirwrkptr != NULL )
- {
- dirblkptr = dirwrkptr ;
- }
- if ( !extendpath(path,pathlen,dirblkptr->dirlist) )
- {
- goto badbuild2 ;
- }
- if ( !buildtree(path,"*",RECURSE_NEVER,(int)dirblkptr->dirlist,
- &dirblkptr->subdirq) )
- {
- goto badbuild2 ;
- }
- path[pathlen] = '\0' ;
- }
-
- /*-----------------------------------------------------------------*/
- /* Arrive here to take TRUE exit to caller indicating that no */
- /* error occurred. If no files were found and no subdirectory */
- /* lists queued, just free the directory list block. Otherwise */
- /* queue it off the caller's subdirectory queue. */
- /*-----------------------------------------------------------------*/
-
- goodbuild:
-
- if ( !found && dirblkptr->subdirq == NULL )
- {
- free(dirblkptr) ;
- }
- else
- {
- dirblkptr->nextptr = *subdirq ;
- *subdirq = dirblkptr ;
- }
- return TRUE ;
-
- /*-----------------------------------------------------------------*/
- /* Arrive here when error occurs to take FALSE exit to caller. */
- /*-----------------------------------------------------------------*/
-
- badbuild1:
-
- beep() ;
-
- badbuild2:
-
- freetree(&dirblkptr->subdirq) ;
- free(dirblkptr) ;
-
- badbuild3:
-
- path[pathlen] = '\0' ;
- return FALSE ;
- }
-
- /*===================================================================*/
- /* */
- /* processtree - process files in directory list */
- /* ----------- */
- /* */
- /* This function processes all the files listed in the tree of */
- /* directory lists created by buildtree, by caller a processing */
- /* function pointed to by global variable "funcptr" for each file in */
- /* turn. It calls itself recursively to handle subdirectories. */
- /* */
- /* The caller provides two arguments: */
- /* */
- /* path - name of the directory including path (if any) and */
- /* leaf-name. */
- /* */
- /* dirblkptr - list of entries in the directory to be processed */
- /* */
- /*===================================================================*/
-
- static enum boolean processtree(
- char *path, /* Ptr to path */
- struct dirblock *dirblkptr) /* Ptr to directory block */
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions. */
- /*-----------------------------------------------------------------*/
-
- int pathlen ; /* Length of path string */
- int i ; /* Working integer */
- char *dataptr ; /* Working pointer */
- struct dirblock *dirwrkptr ; /* Working dir list block ptr */
- _kernel_osfile_block fileblk ; /* OS_File parameter block */
- direntry direntryblk ; /* Directory entry data */
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* First save current path length so that path can be truncated */
- /* to original length after being extending for recursion. */
- /*-----------------------------------------------------------------*/
-
- pathlen = strlen(path) ;
-
- /*-----------------------------------------------------------------*/
- /* Loop through entries in the directory list invoking OS_File to */
- /* read catalog information for the object. */
- /*-----------------------------------------------------------------*/
-
- for ( i = 0 , dataptr = dirblkptr->dirlist ;
- i < dirblkptr->nobjects ;
- i++ , dataptr += strlen(dataptr) + 1 )
- {
- strcpy(path + pathlen,".") ;
- fileblk.start = (int)path ;
- switch ( _kernel_osfile(13,dataptr,&fileblk) )
- {
- /*-------------------------------------------------------------*/
- /* Returned value = 0 (not found). This is unlikely, but could */
- /* occur if the processing function provided by the caller */
- /* gets up to very funny tricks. Issue message and ignore. */
- /*-------------------------------------------------------------*/
-
- case 0 :
-
- printf("'%s.%s' not found\n",path,dataptr) ;
-
- break ;
-
- /*-------------------------------------------------------------*/
- /* Returned value = 1 (file). Bump number of files found and */
- /* copy catalog information into a direntry structure (defined */
- /* in "getdirs.h"). Extract file-type as convenience for the */
- /* processing function (or use -1 if not file-typed). Then */
- /* call the processing function. Abort further processing if */
- /* this returns FALSE. */
- /*-------------------------------------------------------------*/
-
- case 1 :
-
- getdirentrys_counter++ ;
-
- direntryblk.load = fileblk.load ;
- direntryblk.exec = fileblk.exec ;
- direntryblk.length = fileblk.start ;
- direntryblk.attr = fileblk.end ;
- direntryblk.name = dataptr ;
-
- if ( ( fileblk.load & 0xfff00000 ) == 0xfff00000 )
- {
- direntryblk.type = ( fileblk.load & 0x000fff00 ) >> 8 ;
- }
- else
- {
- direntryblk.type = -1 ;
- }
-
- if ( !funcptr(path,&direntryblk) )
- {
- goto badprocess ;
- }
-
- break ;
-
- /*-------------------------------------------------------------*/
- /* Returned value = 2 (directory). Search the queue of */
- /* subdirectory lists using pointer to directory name as */
- /* handle. If found then invoke ourselves recursively to */
- /* process. */
- /*-------------------------------------------------------------*/
-
- case 2 :
-
- for ( dirwrkptr = dirblkptr->subdirq ;
- dirwrkptr != NULL ;
- dirwrkptr = dirwrkptr->nextptr )
- {
- if ( dirwrkptr->handle == (int)dataptr )
- {
- if ( !extendpath(path,pathlen,dataptr) )
- {
- goto badprocess ;
- }
- if ( !processtree(path,dirwrkptr) )
- {
- goto badprocess ;
- }
- break ;
- }
- }
-
- break ;
-
- /*-------------------------------------------------------------*/
- /* Returned value = -2 (error). Issue error message and abort */
- /* any further processing. */
- /*-------------------------------------------------------------*/
-
- case _kernel_ERROR :
-
- printf("%s\n",_kernel_last_oserror()->errmess) ;
- beep() ;
- goto badprocess ;
-
- /*-------------------------------------------------------------*/
- /* Other values should not occur. Again, being paranoid, if */
- /* they do, issue warning message and abort any further */
- /* processing. */
- /*-------------------------------------------------------------*/
-
- default :
-
- printf(invalidentry,dataptr) ;
- beep() ;
- goto badprocess ;
- }
-
- /*---------------------------------------------------------------*/
- /* Truncate path to original length. */
- /*---------------------------------------------------------------*/
-
- path[pathlen] = '\0' ;
- }
-
- /*-----------------------------------------------------------------*/
- /* After all files processed without error, return TRUE. */
- /*-----------------------------------------------------------------*/
-
- return TRUE ;
-
- /*-----------------------------------------------------------------*/
- /* Arrive here on error to return FALSE. */
- /*-----------------------------------------------------------------*/
-
- badprocess:
-
- path[pathlen] = '\0' ;
- return FALSE ;
-
- }
-
- /*===================================================================*/
- /* */
- /* extendpath - add leafname to path */
- /* ---------- */
- /* */
- /* This function provides common support to both "buildtree" and */
- /* "processtree" for extending the current path name with a further */
- /* leafname when recursion is required to process a subdirectory. */
- /* */
- /* It returns TRUE if the path could be extended or FALSE if there */
- /* was not enough room. */
- /* */
- /*===================================================================*/
-
- static enum boolean extendpath(
- char *path, /* Ptr to current path */
- int pathlen, /* Length of current path */
- const char *leafname) /* Ptr to leafname to add */
- {
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* If path would become too long issue error message and take */
- /* FALSE exit (maxpathlen is defined in "getdirs.h"). */
- /* */
- /* Otherwise add period plus leafname to end of path and take */
- /* TRUE exit. */
- /*-----------------------------------------------------------------*/
-
- if ( pathlen + 1 + strlen(leafname) > maxpathlen )
- {
- printf(toolong,path) ;
- beep() ;
- return FALSE ;
- }
-
- path[pathlen] = '.' ;
- strcpy(path + pathlen + 1,leafname) ;
-
- return TRUE ;
- }
-
- /*===================================================================*/
- /* */
- /* freetree - free tree of subdirectory lists */
- /* -------- */
- /* */
- /* This function provides common support to "getdirentrys" and to */
- /* "buildtree". It frees the tree of directory lists queued off */
- /* the anchor word provided by the caller. It calls itself */
- /* recursively to process lists for subdirectories. */
- /* */
- /*===================================================================*/
-
- static void freetree(
- struct dirblock **subdirq) /* Ptr to sub directory queue */
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions. */
- /*-----------------------------------------------------------------*/
-
- struct dirblock *dirblkptr ; /* Directory list block ptr */
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* Run queue of directory lists queued off the anchor word */
- /* provided by caller, freeing the storage allocated to the lists. */
- /* Invoke ourselves recursively to process subdirectory lists. */
- /*-----------------------------------------------------------------*/
-
- while ( ( dirblkptr = *subdirq ) != NULL )
- {
- *subdirq = dirblkptr->nextptr ;
- freetree(&dirblkptr->subdirq) ;
- free(dirblkptr) ;
- }
- }
-
- /*===================================================================*/
- /* */
- /* beep - sound two tone beep to indicate error */
- /* ---- */
- /* */
- /* This function is here simply because I do not like the standard */
- /* beep. Some people may very well think that this is even worse! */
- /* */
- /*===================================================================*/
-
- void beep(void)
- {
- /*-----------------------------------------------------------------*/
- /* Local definitions. */
- /*-----------------------------------------------------------------*/
-
- #define Sound_QSchedule 0x401C1 /* Define SWI number */
-
- #define sound1_delay 0 /* Definition of 1st sound */
- #define sound1_channel 1
- #define sound1_loudness -10
- #define sound1_pitch 10
- #define sound1_duration 4
-
- #define sound2_delay 15 /* Definition of 2nd sound */
- #define sound2_channel 1
- #define sound2_loudness -4
- #define sound2_pitch 0
- #define sound2_duration 7
-
- static _kernel_swi_regs sound1 = /* SWI regs for 1st sound */
- {
- sound1_delay,
- 0,
- (sound1_loudness << 16) | (sound1_channel),
- (sound1_duration << 16) | (sound1_pitch)
- } ;
-
- static _kernel_swi_regs sound2 = /* SWI regs for 2nd sound */
- {
- sound2_delay,
- 0,
- (sound2_loudness << 16) | (sound2_channel),
- (sound2_duration << 16) | (sound2_pitch)
- } ;
-
- _kernel_swi_regs dummy ; /* SWI output regs - ignored */
-
- /*-----------------------------------------------------------------*/
- /* Executable statements */
- /* */
- /* Issue two Sound_QSchedule SWIs to sound two beeps, one after */
- /* the other, the first of a short duration, the second slightly */
- /* longer and also quieter and of lower pitch. */
- /*-----------------------------------------------------------------*/
-
- _kernel_swi(Sound_QSchedule,&sound1,&dummy) ;
- _kernel_swi(Sound_QSchedule,&sound2,&dummy) ;
- }
-
- /*===================================================================*/
-